package cn.quan.evernote;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.THttpClient;
import org.apache.thrift.transport.TTransportException;

import android.util.Log;

import com.evernote.edam.error.EDAMErrorCode;
import com.evernote.edam.error.EDAMNotFoundException;
import com.evernote.edam.error.EDAMSystemException;
import com.evernote.edam.error.EDAMUserException;
import com.evernote.edam.notestore.NoteFilter;
import com.evernote.edam.notestore.NoteList;
import com.evernote.edam.notestore.NoteStore;
import com.evernote.edam.type.Data;
import com.evernote.edam.type.Note;
import com.evernote.edam.type.NoteSortOrder;
import com.evernote.edam.type.Notebook;
import com.evernote.edam.type.Resource;
import com.evernote.edam.type.User;
import com.evernote.edam.userstore.AuthenticationResult;
import com.evernote.edam.userstore.UserStore;

/**
 * Evernote API Interface
 * @author yunfeng.quan@gmail.com
 * @history 12/30 改善
 * TODO 错误信息再fix一下/errMessage不能有空
 * 
 */
final public class SimpleEvernote {
	 // evernote的API Key
	private final String consumerKey = "quanyf";//TODO
	private final String consumerSecret = "";//TODO
	//evernote服务器地址
	private final String evernoteHost = "sandbox.evernote.com";//TODO
    private final String userStoreUrl = "https://" + evernoteHost + "/edam/user";
    private final String noteStoreUrlBase = "https://" + evernoteHost + "/edam/note/";
	//
	UserStore.Client userStore;
	private User user;
	private String authToken;
	private boolean ready;//是否login成功

	private NoteStore.Client noteStore;

	private List<Notebook> notebooks;
	private List<Note> notes;

	private Note createdNote;
	
	SimpleEvernote(String usr,String psw){

		setup(usr,psw);//user,autoToken,noteStore
	}
	//配置API对象
	private void setup(String username,String password){
		ready = authenticate(username,password);
		if(!ready){//登录失败
			return;
		}
		//[noteStore]
		try {
			TBinaryProtocol noteStoreProt = new TBinaryProtocol(new THttpClient(noteStoreUrlBase + user.getShardId()));
			noteStore = new NoteStore.Client(noteStoreProt, noteStoreProt);
		} catch (TTransportException e) {
			errCode = err_network_host;
			errMessage = e.getMessage();
			Log.e(TAG, "#TTransportException happned:" + e.getMessage());
			e.printStackTrace();
			return;
		}		
	}

	//验证用户和密码
	// 成功：设置 user对象，authToken字符串
	private boolean authenticate(String username,String password){
		//create user object => [userStore]
		AuthenticationResult authResult;
		try {
			//URL => http protocol => binary protocol => userStore
			TBinaryProtocol userStoreProt = new TBinaryProtocol(new THttpClient(userStoreUrl));
			userStore = new UserStore.Client(userStoreProt, userStoreProt);
			//登录不顺利，等n秒看看
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			//check protocol version
			boolean versionOk;
			versionOk = userStore.checkVersion(evernote_ver_message,
					com.evernote.edam.userstore.Constants.EDAM_VERSION_MAJOR,
					com.evernote.edam.userstore.Constants.EDAM_VERSION_MINOR);
			if(!versionOk){
				Log.e(TAG, "#Incomatible EDAM client protocol version.");
				return false;
			}
			//[user , authToken]
			authResult = userStore.authenticate(
					username, 
					password,
					consumerKey, 
					consumerSecret);
			Log.d(TAG,"#logged");
			//
			//++result++
			//
			user = authResult.getUser();//user 
			authToken = authResult.getAuthenticationToken();//auth token
		} catch (TTransportException e) {
			errCode = err_network_host;
			errMessage = e.getMessage();
			Log.e(TAG, "#TTransportException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		} catch (TException e) {
			Log.e(TAG, "#TException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		} catch (EDAMUserException e) {
			Log.e(TAG, "#EDAMUserException happned:" + e.getMessage());
			e.printStackTrace();

			String parameter = e.getParameter();
			EDAMErrorCode errorCode = e.getErrorCode();
			
			Log.e(TAG, "#Authentication failed (parameter: " + parameter + " errorCode: " + errorCode + ")");
			errMessage = "#Authentication failed (parameter: " + parameter + " errorCode: " + errorCode + ")";
			
			if (errorCode == EDAMErrorCode.INVALID_AUTH) {
				if (parameter.equals("consumerKey")) {
					errCode = err_other;
					errMessage = "consumer key error";
					if (consumerKey.equals("en-edamtest")) {
						Log.e(TAG, "You must replace the variables consumerKey and consumerSecret with the values you received from Evernote.");
					}else{
						Log.e(TAG, "Your consumer key was not accepted by " + evernoteHost);
					}
					Log.e(TAG, "If you do not have an API Key from Evernote, you can request one from http://www.evernote.com/about/developer/api");
				} else if (parameter.equals("username")) {
					errCode = err_login_user;
					errMessage = "you need a account";
					if (evernoteHost.equals("www.evernote.com") == false) {
						//非法用户
						Log.e(TAG, "Note that your production Evernote account will not work on " + evernoteHost + ",");//TODO
						Log.e(TAG, "you must register for a separate test account at https://" + evernoteHost + "/Registration.action");
					}
				} else if (parameter.equals("password")) {
					errCode = err_login_password;
					errMessage = "The password that you entered is incorrect";
					Log.e(TAG, "The password that you entered is incorrect");//TODO 密码
				}
			}
			return false;
		} catch (EDAMSystemException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMSystemException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	//最近一次登录是否成功
	// true:成功
	// false:失败
	public boolean isReady(){
		return ready;
	}

	public List<Notebook> listNotebooks(){
		//authToken+noteStore => data[notebooks]
		try {
			notebooks = noteStore.listNotebooks(authToken);
		} catch (EDAMUserException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMUserException happned:" + e.getMessage());
			e.printStackTrace();
			return null;
		} catch (EDAMSystemException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMSystemException happned:" + e.getMessage());
			e.printStackTrace();
			return null;
		} catch (TException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#TException happned:" + e.getMessage());
			Log.d(TAG, "#authToken:"+authToken);
			e.printStackTrace();
			return null;
		}
		return notebooks;
	}
	public List<Note> getNotes(Notebook notebook){
		//filter
		NoteFilter filter = new NoteFilter();
		filter.setOrder(NoteSortOrder.CREATED.getValue());
		filter.setAscending(true);
		filter.setNotebookGuid(notebook.getGuid());
		NoteList noteList;
		try {
			noteList = noteStore.findNotes(authToken, filter, 0, 100);
			notes = noteList.getNotes();
		} catch (EDAMUserException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMUserException happned:" + e.getMessage());
			e.printStackTrace();
			return null;
		} catch (EDAMSystemException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMSystemException happned:" + e.getMessage());
			e.printStackTrace();
			return null;
		} catch (TException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#TException happned:" + e.getMessage());
			e.printStackTrace();
			return null;
		} catch (EDAMNotFoundException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#TException happned:" + e.getMessage());
			e.printStackTrace();
			return null;
		}
		return notes;
	}
	public Note createNote(Note note){
		//update
		try {
			//Log.d(TAG,"authToken:"+authToken);
			//Log.d(TAG,"note addr:"+note);
			createdNote = noteStore.createNote(authToken, note);//TODO TimeOut简直功能追加 1.4
		} catch (EDAMUserException e) {
			Log.e(TAG, "#EDAMUserException happned:" + e.getMessage());
			e.printStackTrace();

			String parameter = e.getParameter();
			EDAMErrorCode errorCode = e.getErrorCode();
			
			Log.e(TAG, "#Authentication failed (parameter: " + parameter + " errorCode: " + errorCode + ")");
			errMessage = "#Authentication failed (parameter: " + parameter + " errorCode: " + errorCode + ")";
			
			if (errorCode == EDAMErrorCode.INVALID_AUTH) {
				if (parameter.equals("consumerKey")) {
					errCode = err_other;
					errMessage = "consumer key error";
					if (consumerKey.equals("en-edamtest")) {
						Log.e(TAG, "You must replace the variables consumerKey and consumerSecret with the values you received from Evernote.");
					}else{
						Log.e(TAG, "Your consumer key was not accepted by " + evernoteHost);
					}
					Log.e(TAG, "If you do not have an API Key from Evernote, you can request one from http://www.evernote.com/about/developer/api");
				} else if (parameter.equals("username")) {
					errCode = err_login_user;
					errMessage = "you need a account";
					if (evernoteHost.equals("www.evernote.com") == false) {
						//非法用户
						Log.e(TAG, "Note that your production Evernote account will not work on " + evernoteHost + ",");//TODO
						Log.e(TAG, "you must register for a separate test account at https://" + evernoteHost + "/Registration.action");
					}
				} else if (parameter.equals("password")) {
					errCode = err_login_password;
					errMessage = "The password that you entered is incorrect";
					Log.e(TAG, "The password that you entered is incorrect");//TODO 密码
				}
			}else if(errorCode == EDAMErrorCode.QUOTA_REACHED){
				errCode = err_upload_quota;//超过容量限制
			}else{
				errCode = err_other;
				errMessage = e.getMessage();

			}
			return null;
		} catch (EDAMSystemException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMSystemException happened:"+e.getMessage());
			e.printStackTrace();
			return null;
		} catch (EDAMNotFoundException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMNotFoundException happened:"+e.getMessage());
			e.printStackTrace();
			return null;
		} catch (TException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#TException happened:"+e.getMessage());
			e.printStackTrace();
			return null;
		}
		return createdNote;
	}
	public Note newNote(Notebook notebook){
		Note note = new Note();
		note.setCreated(System.currentTimeMillis());
		note.setUpdated(System.currentTimeMillis());
		note.setActive(true);
		note.setNotebookGuid(notebook.getGuid());
		List<String> tags=new ArrayList<String>();
		tags.add("picmo");
		//note.setTagGuids(tags);
		note.setTagNames(tags);
		
		return note;
	}
	public Resource newResource(String fileName) {
		Resource resource;
		try {
			FileInputStream in;
			in = new FileInputStream(fileName);
			ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
			byte[] block = new byte[10240];
			int len;
			while ((len = in.read(block)) >= 0) {
				byteOut.write(block, 0, len);
			}
			in.close();
			block = null;
			byte[] body = byteOut.toByteArray();
			resource = newResource(body);
			return resource;
		} catch (FileNotFoundException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#FileNotFoundException happened:"+e.getMessage());
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#IOException happened:"+e.getMessage());
			e.printStackTrace();
			return null;
		}
	}
	public Resource newResource(byte[] body) {
		Resource resource = new Resource();
		Data data = new Data();

		data.setSize(body.length);
		try {
			data.setBodyHash(MessageDigest.getInstance("MD5").digest(body));
		} catch (NoSuchAlgorithmException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#NoSuchAlgorithmException happened:"+e.getMessage());
			e.printStackTrace();
			return null;
		}
		data.setBody(body);

		resource.setData(data);
		resource.setMime("image/png");
		return resource;

	}
	//picture memo
	public boolean picmo(String fileName) {
		// Upload to default notebook
		Notebook picmoNotebook = listNotebooks().get(0);//get default notebook
		// file to resource
		Resource picmoResource = newResource(fileName);//resource
		// resource to note
		Note picmoNote = newNote(picmoNotebook);//note
		// set note attribute
		picmoNote.setTitle(note_default_title);
		picmoNote.addToResources(picmoResource);
		String hashHex = bytesToHex(picmoResource.getData().getBodyHash());
		String content= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
				+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
				+ "<en-note>"
				+ "<en-media type=\"image/png\" hash=\"" + hashHex + "\"/>"
				+ "</en-note>";
		picmoNote.setContent(content);

		//upload note to default notebook,
		Log.d(TAG,"#picmo");
		if(createNote( picmoNote)==null){
			Log.e(TAG,"#picmo fail");
			return false;
		}else{
			Log.d(TAG,"#picmo success");
			return true;
		}
	}
	//picture memo
	public boolean picmo(byte[] body) {
		// Upload to default notebook
		Notebook picmoNotebook = listNotebooks().get(0);//get default notebook
		// resource to note
		Note picmoNote = newNote(picmoNotebook);//note
		// file to resource
		Resource picmoResource = newResource(body);//resource
		// set note attribute
		picmoNote.setTitle(note_default_title);
		picmoNote.addToResources(picmoResource);
		String hashHex = bytesToHex(picmoResource.getData().getBodyHash());
		String content= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
				+ "<!DOCTYPE en-note SYSTEM \"http://xml.evernote.com/pub/enml.dtd\">"
				+ "<en-note>"
				+ "<en-media type=\"image/png\" hash=\"" + hashHex + "\"/>"
				+ "</en-note>";
		picmoNote.setContent(content);

		//upload note to default notebook,
		Log.d(TAG,"#picmo");
		if(createNote( picmoNote)==null){
			Log.e(TAG,"#picmo fail");
			return false;
		}else{
			Log.d(TAG,"#picmo success");
			return true;
		}
	}
	private String bytesToHex(byte[] bytes) {
		StringBuilder sb = new StringBuilder();
		for (byte hashByte : bytes) {
			int intVal = 0xff & hashByte;
			if (intVal < 0x10) {
				sb.append('0');
			}
			sb.append(Integer.toHexString(intVal));
		}
		return sb.toString();
	}
	//const
	private final String note_default_title = "Picture MEMO alpha3";
	private final String evernote_ver_message = "SimpleEvernote android/1.0.b3";
	//error information
	private int errCode;
	private String errMessage;
	public final static int err_login_user = 11;
	public final static int err_login_password = 12;
	public final static int err_upload_user = 21;
	public final static int err_upload_password = 22;
	public final static int err_upload_quota = 23;//note exceeds upload quota
	public final static int err_network_host = 31;//host is unresolved 
	public final static int err_other = 90;
	public final static int err_other1 = 91;
	public int getErrCode(){
		return errCode;
	}
	public String getErrMessage(){
		return errMessage;
	}
	
	
	private final String TAG = "**SimpleEvernote**";
	
	/**
	//刷新authToken
	public boolean keepAlive(){
		ready = authenticate();//refresh authtoken
		if(!ready){//登录失败
			return false;
		}

		//[noteStore]
		try {
			final TBinaryProtocol noteStoreProt = new TBinaryProtocol(new THttpClient(noteStoreUrlBase + user.getShardId()));
			noteStore = new NoteStore.Client(noteStoreProt, noteStoreProt);
		} catch (final TTransportException e) {
			errCode = err_network_host;
			errMessage = e.getMessage();
			Log.e(TAG, "#TTransportException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		}	
		return true;
	}	
	private boolean authenticate(){
		AuthenticationResult authResult;
		try {
			authResult = userStore.refreshAuthentication(authToken);
			//
			//++result++
			//
			user = authResult.getUser();//user 
			authToken = authResult.getAuthenticationToken();//auth token
		} catch (TTransportException e) {
			errCode = err_network_host;
			errMessage = e.getMessage();
			Log.e(TAG, "#TTransportException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		} catch (TException e) {
			Log.e(TAG, "#TException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		} catch (EDAMUserException e) {
			Log.e(TAG, "#EDAMUserException happned:" + e.getMessage());
			e.printStackTrace();

			String parameter = e.getParameter();
			EDAMErrorCode errorCode = e.getErrorCode();
			
			Log.e(TAG, "#Authentication failed (parameter: " + parameter + " errorCode: " + errorCode + ")");
			
			if (errorCode == EDAMErrorCode.INVALID_AUTH) {
				if (parameter.equals("consumerKey")) {
					errCode = err_other;
					errMessage = "consumer key error";
					if (consumerKey.equals("en-edamtest")) {
						Log.e(TAG, "You must replace the variables consumerKey and consumerSecret with the values you received from Evernote.");
					}else{
						Log.e(TAG, "Your consumer key was not accepted by " + evernoteHost);
					}
					Log.e(TAG, "If you do not have an API Key from Evernote, you can request one from http://www.evernote.com/about/developer/api");
				} else if (parameter.equals("username")) {
					errCode = err_login_user;
					if (evernoteHost.equals("www.evernote.com") == false) {
						//非法用户
						Log.e(TAG, "Note that your production Evernote account will not work on " + evernoteHost + ",");//TODO
						Log.e(TAG, "you must register for a separate test account at https://" + evernoteHost + "/Registration.action");
					}
				} else if (parameter.equals("password")) {
					errCode = err_login_password;
					Log.e(TAG, "The password that you entered is incorrect");//TODO 密码
				}
			}
			return false;
		} catch (EDAMSystemException e) {
			errCode = err_other;
			errMessage = e.getMessage();
			Log.e(TAG, "#EDAMSystemException happned:" + e.getMessage());
			e.printStackTrace();
			return false;
		}

		return false;
	}
	*/
	
}
